use rocket::{
  http::Status,
  request::{FromRequest, Outcome, Request},
};

use base64::{engine::general_purpose, Engine};

pub struct BasicAuth {
  pub username: String,
  pub password: String,
}

impl BasicAuth {
  fn from_autorization(header: &str) -> Option<Self> {
    let split = header.split_whitespace().collect::<Vec<_>>();
    // Authorization: Basic aGVsbG8gd29ybGQ=
    if split.len() != 2 {
      return None;
    }

    if split[0] != "Basic" {
      return None;
    }

    Self::from_base64_encoded(split[1])
  }

  fn from_base64_encoded(base64_string: &str) -> Option<Self> {
    let decode_bytes = general_purpose::STANDARD.decode(base64_string).unwrap();
    let decoded_str = String::from_utf8(decode_bytes).unwrap();

    // curl -X GET 127.0.0.1:8000/todo/1 -H 'Authorization: Basic aGVsbG8gd29ybGQ='
    // let split = decoded_str.split(' ').collect::<Vec<_>>();
    let split = decoded_str.split_whitespace().collect::<Vec<_>>();

    if split.len() != 2 {
      return None;
    }

    let (username, password) = (split[0].to_string(), split[1].to_string());

    println!("{}\n{}", username, password);

    Some(Self { username, password })
  }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for BasicAuth {
  type Error = ();

  async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
    let auth_header = req.headers().get_one("Authorization");

    if let Some(auth_header) = auth_header {
      if let Some(auth) = Self::from_autorization(auth_header) {
        return Outcome::Success(auth);
      }
    }

    Outcome::Failure((Status::Unauthorized, ()))
  }
}
